import math
from core.config import Config
import xlrd
import xlwt
import numpy as np
import matplotlib.pyplot as plt
import copy

class Base:
    ref = None
    def __init__(self):
        self.ref = [0 for i in range(32)]
    def cal710(self):
        self.ref[31] = 2 * self.ref[30] - self.ref[29]

class WhiteBase(Base):
    """
    白基底
    """
    def __init__(self):
        super(WhiteBase, self).__init__()
        self.name = ""

class BlackBase(Base):
    """
    黑基底
    """
    def __init__(self):
        super(BlackBase, self).__init__()
        self.name = ""

class RelateBase:
    K_by_Sw = None
    S_by_Sw = None
    SD = None
    def __init__(self):
        self.K_by_Sw = [0 for i in range(32)]
        self.S_by_Sw = [0 for i in range(32)]
        self.SD = [0 for i in range(32)]                            # 厚度参数;
        self.vali = [1 for i in range(32)]                          # 该点是否可使用；

class StepBase(RelateBase):
    whiteRef = None
    blackRef = None
    actualRef = None
    whiteRint = None
    blackRint = None
    bWhiteAndBlack = True                   # 黑白底数据都存在；  否则就只有actualRef；
    K_by_S = None
    def __init__(self):
        super(StepBase, self).__init__()
        self.whiteRef = [0 for i in range(32)]
        self.whiteRint =[0 for i in range(32)]
        self.blackRint = [0 for i in range(32)]
        self.blackRef = [0 for i in range(32)]
        self.actualRef = [0 for i in range(32)]
        self.K_by_S = [0 for i in range(32)]

    def calc710(self):
        self.whiteRef[31] = 2 * self.whiteRef[30] - self.whiteRef[29]
        self.blackRef[31] = 2 * self.blackRef[30] - self.blackRef[29]

    def RemoveK1K2AndCalcActualRef(self, K1, whiteBase, blackBase):
        if self.bWhiteAndBlack:                                 # 有黑白底;
            # self.__removeK1(K1)
            self.__dealRefSub()
            self.__removeK1K2(K1)
            self.__calcActual(whiteBase, blackBase)
        else:               # 不存在黑白底；
            self.calcKByS(K1)

    def __dealRefSub(self):
        for i in range(32):
            if self.whiteRef[i] < self.blackRef[i]:         # 理论上黑色背景下的反射率要小于白色背景下的反射率；
                tmp = self.whiteRef[i]
                self.whiteRef[i] = self.blackRef[i]
                self.blackRef[i] = tmp

    def __removeK1(self, Rr):
        for i in range(32):
            self.whiteRint[i] = (self.whiteRef[i] - Rr) /(1 - Rr)
            self.blackRint[i] = (self.blackRef[i] - Rr) / (1 - Rr)

    def __removeK1K2(self, K1):
        """
        去除镜面反射， 内反射；   改为恒定表面修正；
        :param K1:
        :return:
        """
        cfg = Config()
        for i in range(32):
            self.whiteRint[i] = self.whiteRef[i]
            self.blackRint[i] = self.blackRef[i]
        return
        for i in range(32):
            K2 = 0
            rinf = 0.0
            for i in range(32):
                for j in range(8):
                    if j == 0:
                        K2 = 0.6
                    else:
                        K2 = (cfg.gKa2 + cfg.gKb2 * rinf) / (cfg.gKc2 + cfg.gKd2 * rinf)
                    K3 = 1.0 - K1 - K2
                    rinf = (self.whiteRef[i] - K1) / (K3 + K2 * self.whiteRef[i])
                K3 = 1.0 - K1 - K2
                self.whiteRint[i] = (self.whiteRef[i] - K1) / (K3 + K2 * self.whiteRef[i])

        for i in range(32):
            K2 = 0
            rinf = 0.0
            for i in range(32):
                for j in range(8):
                    if j == 0:
                        K2 = 0.6
                    else:
                        K2 = (cfg.gKa2 + cfg.gKb2 * rinf) / (cfg.gKc2 + cfg.gKd2 * rinf)
                    K3 = 1.0 - K1 - K2
                    rinf = (self.blackRef[i] - K1) / (K3 + K2 * self.blackRef[i])
                K3 = 1.0 - K1 - K2
                self.blackRint[i] = (self.blackRef[i] - K1) / (K3 + K2 * self.blackRef[i])

    def __calcActual(self, whiteBase, blackBase):
        for i in range(32):
            a = whiteBase.ref[i] * self.blackRint[i] - blackBase.ref[i] * self.whiteRint[i]    # a = R0 * Rg' - R1 * Rg
            b = self.blackRint[i] + self.blackRint[i] * whiteBase.ref[i] * blackBase.ref[i] +   \
                whiteBase.ref[i] + self.blackRint[i] * self.whiteRint[i] * whiteBase.ref[i] - \
                self.whiteRint[i] - self.whiteRint[i] * whiteBase.ref[i] * blackBase.ref[i] - \
                blackBase.ref[i] - self.blackRint[i] * self.whiteRint[i] * blackBase.ref[i]
            tmpAb = b * b - 4 * a * a
            if tmpAb < 0:
                tmpAb = 0
                print(tmpAb)
            self.actualRef[i] = (b - math.sqrt(tmpAb))/(2 * a)
            self.K_by_S[i] = (1 - self.actualRef[i]) * (1 - self.actualRef[i]) / (2 * self.actualRef[i])

    def calcKByS(self, Rr=0):
        """
        计算K/S;  表面修正预处理；
        :param Rr:
        :return:
        """
        if self.bWhiteAndBlack:                             # 黑白底；
            for i in range(32):
                self.K_by_S[i] = (1 - self.actualRef[i]) * (1 - self.actualRef[i]) / (2 * self.actualRef[i])
        else:                                               # 全遮盖， 一个数据；
            K2 = 0
            rinf = 0.0
            cfg = Config()
            rint = [0] * 32
            for i in range(32):
                for j in range(8):
                    if j == 0:
                        K2 = 0.6
                    else:
                        K2 = (cfg.gKa2 + cfg.gKb2 * rinf) / (cfg.gKc2 + cfg.gKd2 * rinf)
                    K3 = 1.0 - Rr - K2
                    rinf = (self.actualRef[i] - Rr) / (K3 + K2 * self.actualRef[i])
                K3 = 1.0 - Rr - K2
                rint[i] = (self.actualRef[i] - Rr) / (K3 + K2 * self.actualRef[i])
                self.K_by_S[i] = (1 - self.actualRef[i]) * (1 - self.actualRef[i]) / (2 * self.actualRef[i])

# 纯色；
class PureColorant(StepBase):
    """
    纯色；
    """
    def __init__(self):
        super(PureColorant, self).__init__()
        self.colorantType = ""            # 色料类型；

    def calcKSBySw(self, conc):
        """
        计算当前浓度下的K/Sw, S/Sw;   白色的计算；
        :param conc:
        :return:
        """
        for i in range(32):
            self.K_by_Sw[i] = conc/100 * self.K_by_S[i]
            self.S_by_Sw[i] = conc/100

# 梯度；
class StepColorant(StepBase):
    """
    梯度;
    """
    class Compose:
        """
        混合成分;
        """
        def __init__(self):
            self.comp = []
            self.quality = []

    def __init__(self):
        super(StepColorant, self).__init__()
        self.compose = self.Compose()
        self.colorantType = ""              # 色料主色调；s
        self.weightToV = [0 for i in range(32)]

    def calcSD(self, base, pureWhite):
        """
        计算厚度参数；
        :return:
        """
        sumTotal = sum(self.compose.quality)        # 总质量；
        ratio = [0] * len(self.compose.quality)
        for i in range(len(ratio)):
            ratio[i] = self.compose.quality[i] / sumTotal
        for i in range(32):
            if self.S_by_Sw[i] <= 0:
                continue
            try:
                tmpA = (1 - self.whiteRint[i] * self.actualRef[i]) * (self.actualRef[i] - base.ref[i]) / (
                            (1 - base.ref[i] * self.actualRef[i]) * (self.actualRef[i] - self.whiteRint[i]))
                if tmpA < 0:
                    continue
                self.SD[i] = self.actualRef[i] / (1 - self.actualRef[i] * self.actualRef[i]) * math.log(tmpA, math.e)
                tmpRatio = (self.SD[i] / pureWhite.SD[i] - ratio[1]) / self.S_by_Sw[i]
                self.weightToV[i] = tmpRatio
            except:
                pass

    def calcKSBySw(self, baseColorant, pureColorant):
        """
        计算K/Sw, S/Sw
        :param baseColorant:            纯白或者纯黑
        :param pureColorant:            纯色料;
        :return:
        """
        C0 = self.compose.quality[1]      #
        C1 = self.compose.quality[0]
        for i in range(32):
            tmp1 = self.K_by_S[i] - baseColorant.K_by_S[i]
            tmp2 = pureColorant.K_by_S[i] - self.K_by_S[i]
            if tmp1 < 0 or tmp2 < 0:
                self.S_by_Sw[i] = 0
                continue
            self.S_by_Sw[i] = C0 / C1 * tmp1 / tmp2
            self.K_by_Sw[i] = pureColorant.K_by_S[i] * self.S_by_Sw[i]
        self.dealOutlier()

    def dealOutlier(self):
        for i in range(32):
            if self.S_by_Sw[i] > 80:
                if i == 0:
                    self.S_by_Sw[i] = self.S_by_Sw[i+1]
                elif i == 31:
                    self.S_by_Sw[i] = self.S_by_Sw[i-1]
                else:
                    tmpPre = self.S_by_Sw[i-1]
                    tmpNext = self.S_by_Sw[i+1]
                    if tmpPre == 0 and tmpNext != 0:
                        self.S_by_Sw[i] = tmpNext
                    if tmpPre != 0 and tmpNext == 0:
                        self.S_by_Sw[i] = tmpPre
                    if tmpPre != 0 and tmpNext != 0:
                        self.S_by_Sw[i] = (tmpPre + tmpNext)/2
                    if tmpPre == 0 and tmpNext == 0:
                        self.S_by_Sw[i] = 0

    def getC1(self):
        if len(self.compose.quality) == 0:
            return 0
        return self.compose.quality[0]

    def getC0(self):
        if len(self.compose.quality) == 0:
            return 0
        return self.compose.quality[1]

class BlackMixColorant(StepColorant):
    """
    黑混
    """
    def __init__(self):
        super(BlackMixColorant, self).__init__()
        self.K_by_Sw_black = [0] * 32
        self.S_by_Sw_black = [0] * 32                       # 黑混计算得到的；

    def backSSw(self):
        for i in range(32):
            self.K_by_Sw_black[i] = self.K_by_Sw[i]
            self.S_by_Sw_black[i] = self.S_by_Sw[i]

    def calcKSBySw(self, baseColorant, pureColorant):
        """
        计算K/Sw, S/Sw
        :param baseColorant:            纯白或者纯黑
        :param pureColorant:            纯色料;
        :return:
        """
        C0 = self.compose.quality[1]      #
        C1 = self.compose.quality[0]
        for i in range(32):
            tmp1 = self.K_by_S[i] - baseColorant.K_by_S[i]
            tmp2 = pureColorant.K_by_S[i] - self.K_by_S[i]
            if tmp1 * tmp2 < 0:
                self.S_by_Sw[i] = 0
                continue
            self.S_by_Sw[i] = C0 / C1 * tmp1 / tmp2
            self.K_by_Sw[i] = pureColorant.K_by_S[i] * self.S_by_Sw[i]

    def save(self):
        workbook = xlwt.Workbook(encoding='utf-8')
        worksheet = workbook.add_sheet('My Worksheet')
        row = 0
        for i in range(32):
            worksheet.write(row, i, self.S_by_Sw_black[i])
            worksheet.write(row+1, i, self.S_by_Sw[i])
        workbook.save("blackMix" + self.colorantType + ".xlsx")

# 色浆；
class Colorant(RelateBase):
    """
    染料
    """
    def __init__(self):
        super(Colorant, self).__init__()
        self.id = 0             # 色料编号；
        self.name = ""          # 色料名；
        self.step = []          # 梯度；
        self.a = [0] * 32       # 拟合参数；
        self.b = [0] * 32
        self.blackMix = None    # 黑混 ，  有时没有；
        self.colorantType = ""  # 色料类型；
        self.pure = None        # 纯样；
        self.pureWhite = None   # 纯白， 用来限高；
        self.relate = 0         # 相关性；
        self.param = []       # 用于计算K, b,  计算浓度的C1;

    def searchPureData(self, K1, whiteBase, blackBase):
        tmpPure = PureColorant()
        for i in range(32):
            maxIter = 50  # 最大迭代次数；
            spiderNum = 50
            x = [100 * np.random.rand() for j in range(spiderNum)]
            globalX = 0  # 最好的数据；
            globalVal = 0
            spiderBestX = copy.deepcopy(x)
            C1 = C2 = 2  # 学习因子；
            wmax = 0.9
            wmin = 0.4
            vmax = 5  # 最大飞行速度；
            v = 2 * np.random.rand(spiderNum, 1)
            f = lambda kbys, idx: self.__critionFunction(kbys, idx)
            fVal = [0] * spiderNum
            spiderBestVal = [10000] * spiderNum
            curIter = maxIter
            while curIter > 0:
                for j in range(spiderNum):
                    fVal[j] = f(x[j], i)
                    if fVal[j] < spiderBestVal[j]:
                        spiderBestVal[j] = copy.deepcopy(fVal[j])
                        spiderBestX[j] = copy.deepcopy(x[j])
                globalVal = np.min(spiderBestVal)
                tmpIdx = spiderBestVal.index(globalVal)
                globalX = copy.deepcopy(spiderBestX[tmpIdx])
                for k in range(spiderNum):
                    w = (wmax - wmin) * (maxIter - curIter) / maxIter + wmin
                    v[k] = w * v[k] + C1 * np.random.rand() * (spiderBestX[k] - x[k]) + C2 * np.random.rand() * (globalX - x[k])
                    if v[k] > vmax:
                        v[k] = vmax
                    if v[k] < - vmax:
                        v[k] = -vmax
                    x[k] = x[k] + v[k]
                    if x[k] < 0:
                        x[k] = 0.0001
                curIter -= 1
            if globalVal > 1000:
                print(0)
                self.pure.K_by_S[i] = 0
            else:
                print(globalX)
                self.pure.K_by_S[i] = float(globalX)
        for i in range(32):
            if self.pure.K_by_S[i] <= 0:
                for j in range(i-1, 0, -1):
                    if self.pure.K_by_S[j] > 0:
                        self.pure.K_by_S[i] = copy.deepcopy(self.pure.K_by_S[j])
                if self.pure.K_by_S[i] > 0:
                    continue
                for j in range(i+1, 32, 1):
                    if self.pure.K_by_S[j] > 0:
                        self.pure.K_by_S[i] = copy.deepcopy(self.pure.K_by_S[j])

    def checkStep(self, bBaseWhite):
        """
        检测单色还原度；
        :param bBaseWhite:
        :return:
        """
        pass



    def __critionFunction(self, kbys, idx):
        sumSub = 0
        if kbys < 0:
            return sumSub
        for j in range(len(self.step)):
            tmpSSw = (self.step[j].K_by_S[idx] - self.pureWhite.K_by_S[idx]) / (kbys - self.step[j].K_by_S[idx])  # s/Sw
            if tmpSSw < 0:
                sumSub = 10000
                break
            try:
                tmpKSw = kbys * tmpSSw  # k/Sw
                tmpC0 = self.step[j].getC0()
                tmpC1 = self.step[j].getC1()
                tmpKSMix = (tmpC0 * self.pureWhite.K_by_S[idx] + tmpC1 * tmpKSw) / (tmpC0 + tmpC1 * tmpSSw)  # K/S
                # tmpRint = 1.0 + tmpKSMix - math.sqrt(tmpKSMix * tmpKSMix + 2 * tmpKSMix)                        # Rint
                # tmpSD = tmpC0/(tmpC1 + tmpC0) * self.pureWhite.SD[i] + tmpC1/(tmpC0 + tmpC1) * tmpSSw * self.pureWhite.SD[i]  #SD
                # tmp1 = (whiteBase.ref[i] - tmpRint)/(tmpRint * tmpRint) + (1/tmpRint - whiteBase.ref[i]) * math.pow(math.e, tmpSD * (1/tmpRint - tmpRint))
                # tmp2 = (whiteBase.ref[i] - tmpRint) + (1/tmpRint - whiteBase.ref[i]) * math.pow(math.e, tmpSD * (1/tmpRint - tmpRint))
                # tmpRefWhite = tmpRint * tmp1/tmp2                                                           # 内反射率；
                sumSub += math.fabs(tmpKSMix - self.step[j].K_by_S[idx])
            except:
                sumSub = 10000
                break
        return sumSub

    def getVolumeRatio(self, conc):
        """
        计算体积比；
        :param conc:
        :return:
        """
        ratio = [0] * 32
        for i in range(32):
            ratio[i] = self.param[i][0] * math.pow(conc, 3) + self.param[i][1] * math.pow(conc, 2) + self.param[i][2] * math.pow(conc, 1) + self.param[i][3]
        return ratio

    def fitSBySw(self):
        for j in range(32):
            x = []
            y = []
            for i in range(len(self.step)-1, 0, -1):
                tmpcc = math.log(self.step[i].getC1() / (self.step[i].getC1() + self.step[i].getC0()) * 100, math.e)
                tmpSbySw = self.step[i].S_by_Sw[j]
                if tmpSbySw < 0:
                    continue
                x.append(tmpcc)
                y.append(tmpSbySw)
            A = np.zeros((len(x), 2))
            B = np.zeros((len(y), 1))
            for i in range(len(x)):
                A[i][0] = 1
                A[i][1] = x[i]
                B[i][0] = y[i]
            ATA = A.T.dot(A)
            ATB = A.T.dot(B)
            tmpRes = np.linalg.inv(ATA).dot(ATB)
            self.a[j] = tmpRes[0]
            self.b[j] = tmpRes[1]

    def testFit(self):
        """
        拟合检验：
        :return:
        """
        fig1 = plt.figure(1, figsize=(12, 10))
        for i in range(0, 32, 2):
            ax = fig1.add_subplot(4, 4, int(i/2) + 1)
            x = []
            y = []
            x2= []
            y2 = []
            for j in range(len(self.step)):
                tmpcc = self.step[j].getC1() / (self.step[j].getC1() + self.step[j].getC0()) * 100
                tmpSbySw = self.step[j].S_by_Sw[i]
                x2.append(tmpcc)
                if tmpSbySw > 0:
                    y.append(tmpSbySw)
                    x.append(tmpcc)
                tmpCalc = self.a[i] + self.b[i] * math.log(tmpcc, math.e)
                y2.append(tmpCalc)
            ax.plot(x, y, linestyle='-', alpha=0.8, color='r')
            ax.plot(x2, y2, linestyle='-', alpha=0.8, color='g')
        plt.show()

    def dealLowRef(self):
        """
        对低反射率段进行简单排序；
        :param threshod:
        :return:
        """
        for j in range(32):
            tmpRef = []
            for i in range(len(self.step)):
                if self.step[i].whiteRef[j] < self.pure.whiteRef[j]:            # 纯样最小；
                    tmp = self.pure.whiteRef[j]
                    self.pure.whiteRef[j] = self.step[i].whiteRef[j]
                    self.step[i].whiteRef[j] = tmp
            for i in range(len(self.step)):
                tmpRef.append(self.step[i].whiteRef[j])
            tmpRef = np.array(tmpRef)
            tmpRef = np.sort(tmpRef)
            for i in range(len(self.step)):
                self.step[i].whiteRef[j] = tmpRef[i]

            tmpRef2 = []
            for i in range(len(self.step)):
                if self.step[i].blackRef[j] < self.pure.blackRef[j]:            # 纯样最小；
                    tmp = self.pure.blackRef[j]
                    self.pure.blackRef[j] = self.step[i].blackRef[j]
                    self.step[i].blackRef[j] = tmp
            for i in range(len(self.step)):
                tmpRef2.append(self.step[i].blackRef[j])
            tmpRef2 = np.array(tmpRef2)
            tmpRef2 = np.sort(tmpRef2)
            for i in range(len(self.step)):
                self.step[i].blackRef[j] = tmpRef2[i]

    def dealBlackMix(self):
        """
        黑混处理， 解决高波段
        :return:
        """
        if not self.blackMix:
            return
        for i in range(32):
            for j in range(len(self.step)):
                ssw = self.step[j].S_by_Sw[i]
                if ssw <= 0 or self.pureWhite.K_by_S[i] > self.step[j].K_by_S[i]:                # 如果为负， 或者超过纯白， 那么就使用黑混结果；
                    self.step[j].S_by_Sw[i] = self.blackMix.S_by_Sw[i]
                    self.step[j].K_by_Sw[i] = self.blackMix.K_by_Sw[i]

    def calcKSBySw(self, conc):
        """
        计算对应浓度的K/Sw, S/Sw
        :param conc:
        :return:
        """
        bFit = False
        if bFit:
            for i in range(32):
                if conc == 0:
                    self.S_by_Sw[i] = 0
                else:
                    self.S_by_Sw[i] = self.a[i] + self.b[i] * math.log(conc, math.e)
                self.K_by_Sw[i] = self.pure.K_by_S[i] * self.S_by_Sw[i]
        else:
            for i in range(32):
                x = []
                y = []
                yy = []
                for j in range(len(self.step)):
                    tmpcc = self.step[j].getC1() / (self.step[j].getC1() + self.step[j].getC0()) * 100
                    tmpSbySw = self.step[j].S_by_Sw[i]
                    tmpKbySw = self.step[j].K_by_Sw[i]
                    if tmpSbySw > 0:
                        x.append(tmpcc)
                        y.append(tmpSbySw)
                        yy.append(tmpKbySw)
                # 插值；
                if (x[0] - conc) * (x[len(x) - 1] - conc) < 0:
                    idx = 0
                    for k in range(1, len(x)):
                        if (x[k] - conc) * (x[k-1] - conc) <= 0:
                            idx = k
                            break
                    x1 = x[idx-1]
                    x2 = x[idx]
                    y1 = y[idx - 1]
                    y2 = y[idx]
                    y0 = (conc - x2)/(x1-x2) * (y1-y2) + y2
                    self.S_by_Sw[i] = float(y0)
                    self.K_by_Sw[i] = self.pure.K_by_S[i] * self.S_by_Sw[i]
                    # self.K_by_Sw[i] = float((conc - x2)/(x1-x2) * (yy[idx-1] - yy[idx]) + yy[idx])
                elif math.fabs(x[0] - conc) > math.fabs(x[len(x) - 1] - conc):
                    # self.K_by_Sw[i] = yy[len(yy) - 1]
                    self.S_by_Sw[i] = y[len(y) - 1]
                    self.K_by_Sw[i] = self.pure.K_by_S[i] * self.S_by_Sw[i]
                elif math.fabs(x[0] - conc) < math.fabs(x[len(x) - 1] - conc):
                    # self.K_by_Sw[i] = yy[0]
                    self.S_by_Sw[i] = y[0]
                    self.K_by_Sw[i] = self.pure.K_by_S[i] * self.S_by_Sw[i]

# 色浆组；
class ColorantGroup:                            # 染料组类型；
    """
    染料组
    """
    def __init__(self, name):
        self.groupName = name       # 组名；
        self.pureWhite = None       # 基准白；
        self.pureBlack = None       # 纯黑；
        self.baseWhite = None       # 白底;
        self.baseBlack = None       # 黑底；
        self.calibrateBlack = None  # 标定黑；
        self.colorants = []         # 所有的色料;
        self.stdSmp = None          # 标样；
        self.K1 = 0.04              # 表面反射；

    def prepare(self):
        """
        预处理；
        :return:
        """
        for i in range(len(self.colorants)):
            self.colorants[i].dealLowRef()

    def calcSD(self):
        """
        计算厚度参数;
        :return:
        """
        # 纯白的SD；
        testWhiteRint =[0] * 32
        for i in range(32):
            tmpRinf = self.pureWhite.actualRef[i]
            tmpR = self.pureWhite.blackRint[i]
            tmpRg = self.baseBlack.ref[i]
            tmpX = (1 - tmpR * tmpRinf) * (tmpRinf - tmpRg)/((1 - tmpRg * tmpRinf) * (tmpRinf - tmpR))
            self.pureWhite.SD[i] = tmpRinf/(1 - tmpRinf * tmpRinf) * math.log(tmpX, math.e)
            tmp1 = (self.baseWhite.ref[i] - tmpRinf)/(tmpRinf * tmpRinf)
            tmp2 = (1/tmpRinf - self.baseWhite.ref[i]) * math.pow(math.e, self.pureWhite.SD[i] * (1/tmpRinf - tmpRinf))
            tmp3 = self.baseWhite.ref[i] - tmpRinf + tmp2
            testWhiteRint[i] = tmpRinf * (tmp1 + tmp2)/tmp3

        # 计算梯度样本的SD；
        for i in range(len(self.colorants)):
            for j in range(len(self.colorants[i].step)):
                for k in range(32):
                    self.colorants[i].step[j].SD[k] = self.colorants[i].step[j].S_by_Sw[k] * self.pureWhite.SD[k]


    def calcPureWhiteKSw(self):
        """
        处理纯白；
        :return:
        """
        if not self.pureWhite:
            return
        for i in range(32):
            self.pureWhite.K_by_Sw[i] = self.pureWhite.K_by_S[i]
            self.pureWhite.S_by_Sw[i] = 1

    def saveKbyS(self):
        """
        保存K/S;
        :return:
        """
        workbook = xlwt.Workbook(encoding='utf-8')
        worksheet = workbook.add_sheet('My Worksheet')
        row = 0
        for i in range(len(self.colorants)):  # 首先保存色料梯度；
            for j in range(len(self.colorants[i].step)):
                worksheet.write(row, 0, self.colorants[i].step[j].compose.comp[0] + " " + str(
                    self.colorants[i].step[j].compose.quality[0]))
                for k in range(32):
                    worksheet.write(row, k + 1, self.colorants[i].step[j].K_by_S[k])
                row += 1
            if self.colorants[i].blackMix:
                worksheet.write(row, 0, "黑混")
                for k in range(32):
                    worksheet.write(row, k + 1, self.colorants[i].blackMix.K_by_S[k])
                row += 1
            if self.colorants[i].pure:
                worksheet.write(row, 0, "纯"+ self.colorants[i].pure.colorantType)
                for k in range(32):
                    worksheet.write(row, k + 1, self.colorants[i].pure.K_by_S[k])
                row += 1

        row += 1
        # 保存纯白;
        worksheet.write(row, 0, "纯白")
        for k in range(32):
            worksheet.write(row, k + 1, self.pureWhite.K_by_S[k])
        row += 1

        # 保存纯黑
        worksheet.write(row, 0, "纯黑")
        for k in range(32):
            worksheet.write(row, k + 1, self.pureBlack.K_by_S[k])

        workbook.save("K_By_S.xlsx")

    def save(self):
        workbook = xlwt.Workbook(encoding='utf-8')
        worksheet = workbook.add_sheet('My Worksheet')
        row = 0
        for i in range(len(self.colorants)):            # 首先保存色料梯度；
            for j in range(len(self.colorants[i].step)):
                worksheet.write(row, 0, self.colorants[i].step[j].compose.comp[0] + " " + str(self.colorants[i].step[j].compose.quality[0]))
                for k in range(32):
                    # worksheet.write(row, k + 1, self.colorants[i].step[j].K_by_Sw[k])
                    worksheet.write(row, k + 1, float(self.colorants[i].step[j].S_by_Sw[k]))
                row += 1
            if self.colorants[i].blackMix:
                worksheet.write(row, 0, "黑混")
                for k in range(32):
                    worksheet.write(row, k+1, self.colorants[i].blackMix.S_by_Sw[k])
                row += 1

        row += 1
        # 保存纯白;
        worksheet.write(row, 0, "纯白")
        for k in range(32):
            # worksheet.write(row, k+1,self.pureWhite.K_by_Sw[k])
            worksheet.write(row, k+1, self.pureWhite.S_by_Sw[k])
        row += 1

        # 保存纯黑
        worksheet.write(row, 0, "纯黑")
        for k in range(32):
            worksheet.write(row, k+1, self.pureBlack.S_by_Sw[k])

        workbook.save("KS_by_Sw.xlsx")

class Sample:
    """
    标样；
    """
    ref = None
    xyz = None
    lab = []
    def __init__(self):
        self.name = ""                      # 样本名；
        self.ref = [0 for i in range(32)]
        self.K_by_S = [0] * 32
        self.actualRef = [0 for i in range(32)]
        self.xyz = [0 for i in range(3)]
        self.lab = [0 for i in range(3)]
        self.D65 = [82.80,
                    91.50,
                    93.40,
                    86.70,
                    104.90,
                    117.00,
                    117.80,
                    114.90,
                    115.90,
                    108.80,
                    109.40,
                    107.80,
                    104.80,
                    107.70,
                    104.40,
                    104.00,
                    100.00,
                    96.30,
                    95.80,
                    88.70,
                    90.00,
                    89.60,
                    87.70,
                    83.30,
                    83.70,
                    80.00,
                    80.20,
                    82.30,
                    78.30,
                    69.70,
                    71.60,
                    74.30]
        self.angle10 = [
            [0.0191, 0.0020, 0.0860],
            [0.0847, 0.0088, 0.3894],
            [0.2045, 0.0214, 0.9725],
            [0.3147, 0.0387, 1.5535],
            [0.3837, 0.0621, 1.9673],
            [0.3707, 0.0895, 1.9948],
            [0.3023, 0.1282, 1.7454],
            [0.1956, 0.1852, 1.3176],
            [0.0805, 0.2536, 0.7721],
            [0.0162, 0.3391, 0.4153],
            [0.0038, 0.4608, 0.2185],
            [0.0375, 0.6067, 0.1120],
            [0.1177, 0.7618, 0.0607],
            [0.2365, 0.8752, 0.0305],
            [0.3768, 0.9620, 0.0137],
            [0.5298, 0.9918, 0.0040],
            [0.7052, 0.9973, 0.0000],
            [0.8787, 0.9556, 0.0000],
            [1.0142, 0.8689, 0.0000],
            [1.1185, 0.7774, 0.0000],
            [1.1240, 0.6583, 0.0000],
            [1.0305, 0.5280, 0.0000],
            [0.8563, 0.3981, 0.0000],
            [0.6475, 0.2835, 0.0000],
            [0.4316, 0.1798, 0.0000],
            [0.2683, 0.1076, 0.0000],
            [0.1526, 0.0603, 0.0000],
            [0.0813, 0.0318, 0.0000],
            [0.0409, 0.0159, 0.0000],
            [0.0199, 0.0077, 0.0000],
            [0.0096, 0.0037, 0.0000],
            [0.0046, 0.0018, 0.0000]]
        self.TE = []
        self.__xnynzn = [0] * 3
        self.deltaE = 0                     # 色差;
        self.deltaLab = [0] * 3
        self.xsysns = np.zeros((32, 3))
        self.__initIlum()

    def __initIlum(self):
        for i in range(32):
            for j in range(3):
                self.xsysns[i][j] = self.angle10[i][j] * self.D65[i]
        for i in range(32):
            self.__xnynzn[1] += self.xsysns[i][1]
        alphaS = 100.0 / self.__xnynzn[1]
        self.__xnynzn[0] = self.__xnynzn[2] = 0
        self.__xnynzn[1] = 100.0
        for i in range(32):
            self.xsysns[i][1] *= alphaS
            self.xsysns[i][0] *= alphaS
            self.xsysns[i][2] *= alphaS
            self.__xnynzn[0] += self.xsysns[i][0]
            self.__xnynzn[2] += self.xsysns[i][2]

    def calcActualRef(self, Rr):
        K2 = 0
        K3 = 0
        rinf = 0.0
        cfg = Config()
        rint = [0] * 32
        for i in range(32):
            for j in range(8):
                if j == 0:
                    K2 = 0.6
                else:
                    K2 = (cfg.gKa2 + cfg.gKb2 * rinf) / (cfg.gKc2 + cfg.gKd2 * rinf)
                K3 = 1.0 - Rr - K2
                rinf = (self.ref[i] - Rr) / (K3 + K2 * self.ref[i])
            K3 = 1.0 - Rr - K2
            self.actualRef[i] = (self.ref[i] - Rr) / (K3 + K2 * self.ref[i])
            self.K_by_S[i] = (1 - self.actualRef[i]) * (1 - self.actualRef[i]) / (2 * self.actualRef[i])

    def loadSmp(self, excelPath):
        data = xlrd.open_workbook(excelPath)
        self.sheet = data.sheet_by_index(0)
        self.name = self.sheet.cell_value(1, 0)
        for i in range(31):
            self.ref[i] = self.sheet.cell_value(1, i + 1) * 0.01
        self.ref[31] = 2 * self.ref[30] - self.ref[29]

    def __initXYZ(self):
        for j in range(3):
            self.xyz[j] = 0

    def calcXYZ(self):
        self.__initXYZ()
        for i in range(32):
            for j in range(3):
                self.xyz[j] += self.xsysns[i][j] * self.ref[i]

    def xyzToLab(self):
        rap = [0] * 3
        seuil = 0.008856
        tiers = 1.0 / 3.0
        for i in range(3):
            rap[i] = self.xyz[i] / self.__xnynzn[i]

        if rap[1] > seuil:
            coefY = math.pow(rap[1], tiers)
            self.lab[0] = 116 * coefY - 16.0
        else:
            coefY = 7.787 * rap[1]
            self.lab[0] = 903.29 * rap[1]

        if rap[0] > seuil:
            coefX = math.pow(rap[0], tiers)
        else:
            coefX = 7.787 * rap[0]

        if rap[2] > seuil:
            coefZ = math.pow(rap[2], tiers)
        else:
            coefZ = 7.787 * rap[2]
        self.lab[1] = 500.0 * (coefX - coefY)
        self.lab[2] = 200.0 * (coefY - coefZ)

    def calcDeltaE(self, smp):
        self.calcXYZ()
        self.xyzToLab()
        smp.calcXYZ()
        smp.xyzToLab()
        for i in range(3):
            self.deltaLab[i] = smp.lab[i] - self.lab[i]
        self.deltaE = math.sqrt(self.deltaLab[0] * self.deltaLab[0] + self.deltaLab[1] * self.deltaLab[1] + self.deltaLab[2] * self.deltaLab[2])

class Formula:
    """
    配方；
    """
    class Ingredient:
        def __init__(self):
            self.colorants = None           # 色料;  白  其他色料；
            self.quality = 0                # 含量；

    def __init__(self):
        self.name = ""                                                      # 配方名；
        self.K_by_S = [0] * 32                                              # 混合Ｋ／Ｓ；
        self.colorantsComp = [self.Ingredient() for i in range(6)]          # 默认最大成分为6个；
        self.nComp = 0                                                      # 成分数目；
        self.SDMix = [0] * 32                                               # 混合厚度参数；
        self.actualRef = [0] * 32                                           # 真实反射率；
        self.rint = [0] * 32                                                # 内反射率
        self.ref = [0] * 32                                                 # 这里有矛盾， 这里会是包含镜面反射，内反射的；
        self.R0 = [0] * 32                                                  # 全黑基底下的反射率；

    def calcSDMix(self, pureWhite):
        """
        计算混合的厚度参数；
        :param pureWhite:
        :return:
        """
        sumQuality = 0
        for i in range(self.nComp):
            sumQuality += self.colorantsComp[i].quality
        for i in range(32):
            self.SDMix[i] = self.colorantsComp[0].quality / sumQuality * pureWhite.SD[i]
        for j in range(1, self.nComp):
            # weightRatio = self.colorantsComp[j].colorants.getVolumeRatio(self.colorantsComp[j].quality / sumQuality)
            weightRatio = self.colorantsComp[j].quality / sumQuality
            for i in range(32):                         # 混合厚度参数；
                try:
                    self.SDMix[i] += weightRatio * self.colorantsComp[j].colorants.S_by_Sw[i] * pureWhite.SD[i]                   # 这里S/Sw已经乘以浓度
                except:
                    self.SDMix[i] = self.SDMix[i - 1]
        for i in range(32):
            if self.SDMix[i] < 0:
                # 左右查找；
                for j in range(i-1, 0, -1):
                    if self.SDMix[j] > 0:
                        self.SDMix[i] = copy.deepcopy(self.SDMix[j])
                        break
                if self.SDMix[i] > 0:
                    continue
                for j in range(i+1, 32, 1):
                    if self.SDMix[j] > 0:
                        self.SDMix[i] = copy.deepcopy(self.SDMix[j])
                        break

    def calcKByS(self):
        """
        混合公式计算K/S;
        :return:
        """
        for j in range(32):
            sum1 = 0
            sum2 = 0
            for i in range(self.nComp):
                sum1 += self.colorantsComp[i].colorants.K_by_Sw[j] * self.colorantsComp[i].quality
                sum2 += self.colorantsComp[i].colorants.S_by_Sw[j] * self.colorantsComp[i].quality
            self.K_by_S[j] = float(sum1/sum2)

    def calcRint(self, K1):
        """
        计算内反射率；
        :return:
        """
        for i in range(32):
            self.rint[i] = 1.0 + self.K_by_S[i] - math.sqrt(self.K_by_S[i] * self.K_by_S[i] + 2 * self.K_by_S[i])                    # 计算得到内放射率；

    def calcR0(self):
        """
        计算背景Rg为0时的真实反射率；
        :return:
        """
        for i in range(32):
            try:
                tmp1 = 1 - math.pow(math.e, self.SDMix[i] * (1/self.rint[i] - self.rint[i]))
                tmp2 = self.rint[i] - 1/self.rint[i] * math.pow(math.e, self.SDMix[i] *(1/self.rint[i] - self.rint[i]))
                self.R0[i] = tmp1 / tmp2
            except:
                self.R0[i] = self.R0[i - 1]

    def calcR(self, base):
        """
        计算反射率；
        :return:
        """
        for i in range(32):
            tmpRg = base.ref[i]                 # 背景；
            self.ref[i] = (tmpRg + self.R0[i] - tmpRg * self.R0[i] * (1/self.rint[i] + self.rint[i]))/(1 - tmpRg * self.R0[i])

    def calcRef(self, K1, cfg):
        """
        桑德森反算总反射率；
        :param K1:
        :param cfg:
        :return:
        """
        for i in range(32):
            K2 = (cfg.gKa2 + cfg.gKb2 * self.ref[i]) / (cfg.gKc2 + cfg.gKd2 * self.ref[i])
            K3 = 1.0 - K1 - K2
            self.ref[i] = (K1 + K3 * self.ref[i]) / (1 - K2 * self.ref[i])

    def calcRef2(self, Rr):
        """
        恒定表面；
        :param Rr:
        :return:
        """
        for i in range(32):
            self.ref[i] = Rr + (1 - Rr) * self.ref[i]